package model.components.networks.network;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import edu.uci.ics.jung.graph.Graph;

import model.components.graphs.graph.SparseMultigraphGraph;
import model.components.links.comparator.LinkNumberComparator;
import model.components.links.link.Link;
import model.components.links.link.PhysicalLink;
import model.components.nodes.comparator.NodeNumberComparator;
import model.components.nodes.node.PhysicalNode;
import model.components.nodes.node.Node;

public class PhysicalNetwork extends Network
{	
	private int cpuUnitTimeUnitPrice;
	public int getCpuUnitTimeUnitPrice(){ return cpuUnitTimeUnitPrice; }
	public void setCpuUnitTimeUnitPrice( int cpuUnitTimeUnitPrice ){ this.cpuUnitTimeUnitPrice = cpuUnitTimeUnitPrice; }
	
	private int memoryUnitTimeUnitPrice;
	public int getMemoryUnitTimeUnitPrice(){ return memoryUnitTimeUnitPrice; }
	public void setMemoryUnitTimeUnitPrice( int memoryUnitTimeUnitPrice ){ this.memoryUnitTimeUnitPrice = memoryUnitTimeUnitPrice; }
	
	private int diskSpaceUnitTimeUnitPrice;
	public int getDiskSpaceUnitTimeUnitPrice(){ return diskSpaceUnitTimeUnitPrice; }
	public void setDiskSpaceUnitTimeUnitPrice( int diskSpaceUnitTimeUnitPrice ){ this.diskSpaceUnitTimeUnitPrice = diskSpaceUnitTimeUnitPrice; }

	private int bandwidthUnitTimeUnitPrice;
	public int getBandwidthUnitTimeUnitPrice(){ return bandwidthUnitTimeUnitPrice; }
	public void setBandwidthUnitTimeUnitPrice( int bandwidthUnitTimeUnitPrice ){ this.bandwidthUnitTimeUnitPrice = bandwidthUnitTimeUnitPrice; }

	private int networkRevenue;
	public int getNetworkRevenue(){ return networkRevenue; }
	public void setNetworkRevenue( int networkRevenue ){ this.networkRevenue = networkRevenue; }
	
	private boolean selected = false;
	public boolean isSelected(){ return selected; }
	public void setSelected( boolean selected ){ this.selected = selected; }
	
	public PhysicalNetwork( String namePrefix )
	{
		super( namePrefix, 0, new SparseMultigraphGraph() );
	}
	
	public PhysicalNetwork( String namePrefix, int number, int cpuUnitPrice, int memoryUnitPrice, int diskSpaceUnitPrice, int bandwidthUnitPrice ) 
	{
    	super( namePrefix, number, new SparseMultigraphGraph() );
    	
    	this.setCpuUnitTimeUnitPrice( cpuUnitPrice );
    	this.setMemoryUnitTimeUnitPrice( memoryUnitPrice );
    	this.setDiskSpaceUnitTimeUnitPrice( diskSpaceUnitPrice );
    	this.setBandwidthUnitTimeUnitPrice( bandwidthUnitPrice );
    }
	
	public PhysicalNetwork( String namePrefix, int number, Graph< Node, Link > graph, int cpuUnitPrice, int memoryUnitPrice, int diskSpaceUnitPrice, int bandwidthUnitPrice ) 
	{
    	super( namePrefix, number, graph );
    	
    	this.setCpuUnitTimeUnitPrice( cpuUnitPrice );
    	this.setMemoryUnitTimeUnitPrice( memoryUnitPrice );
    	this.setDiskSpaceUnitTimeUnitPrice( diskSpaceUnitPrice );
    	this.setBandwidthUnitTimeUnitPrice( bandwidthUnitPrice );
    }
	
	public PhysicalNetwork getCopy()
    {
		PhysicalNetwork physicalNetwork = new PhysicalNetwork( this.getNamePrefix(), this.getNumber(), ( (SparseMultigraphGraph) this.getGraph() ).getCopy(), this.getCpuUnitTimeUnitPrice(), this.getMemoryUnitTimeUnitPrice(), this.getDiskSpaceUnitTimeUnitPrice(), this.getBandwidthUnitTimeUnitPrice() );
		physicalNetwork.setState( this.getState() );
    	physicalNetwork.setChange( this.isChange() );
    	physicalNetwork.setTimeStamp( this.getTimeStamp() );
    	
    	return physicalNetwork;
    }
	
	public List< PhysicalNode > getPhysicalNodes()
	{
		List< PhysicalNode > physicalNodes = new ArrayList< PhysicalNode >();
		
		for( Node node: this.getNodes() )
			physicalNodes.add( ( PhysicalNode )node );
		
		Collections.sort( physicalNodes, new NodeNumberComparator() );
		
		return physicalNodes;
	}
	
	public double[][] getPhysicalNodesAvailableCapacities()
	{
		double physicalNodesAvailableCapacities[][] = new double[ 3 ][ this.getPhysicalNodes().size() ];
		
		for( int i = 0; i < this.getNodes().size(); i++ )
		{  
			PhysicalNode physicalNode = this.getPhysicalNodes().get( i );
			
			physicalNodesAvailableCapacities[ 0 ][ i ] = physicalNode.getAvailableCpu();
			physicalNodesAvailableCapacities[ 1 ][ i ] = physicalNode.getAvailableMemory();
			
			if( physicalNode.getType().equals( Node.SERVER_TYPE ) )
				physicalNodesAvailableCapacities[ 2 ][ i ] = physicalNode.getAvailableDiskSpace();
		}
		
		return physicalNodesAvailableCapacities;
	}
		
    public List< PhysicalLink > getPhysicalLinks()
    {
    	List< PhysicalLink > physicalLink = new ArrayList< PhysicalLink >();
		
		for( Link link: this.getLinks() )
			physicalLink.add( (PhysicalLink) link );
		
		Collections.sort( physicalLink, new LinkNumberComparator() );
    	
    	return physicalLink;
	}
    
	public double[][] getPhysicalLinksAvailableBandwidths()
	{
		double physicalLinksAvailableBandwidths[][] = new double[ this.getNodes().size() ][ this.getNodes().size() ];
		
		for( PhysicalLink physicalLink: this.getPhysicalLinks() )
		{
			physicalLinksAvailableBandwidths[ physicalLink.getFirstNode().getNumber()  ][ physicalLink.getSecondNode().getNumber() ] = physicalLink.getAvailableBandwidth();
			physicalLinksAvailableBandwidths[ physicalLink.getSecondNode().getNumber() ][ physicalLink.getFirstNode().getNumber()  ] = physicalLink.getAvailableBandwidth();
		}
		
		return physicalLinksAvailableBandwidths;
	}
	
}
